import os
import random
from abc import ABCMeta, abstractmethod
from typing import Optional, List, Tuple
from sqlalchemy.orm import Session
from app.controller.model.compute import ComputeScaleEnum, ComputeTypeEnum
from app.dao.model.storage import Storage, Port
from app.docker import Client
from app.dao.compute import create_compute
from app.dao.model.compute import Compute
from app.utils.rand import get_new_rand_str
from app.controller.DockerSwarmCtl import GetNodeList
import datetime


def check_name(name: str):
    return True


def get_new_name(prefix: str = ''):
    name = get_new_rand_str()
    return prefix + name


def commit_compute(db: Session, *, service_id: str,
                   mainnode: str,
                   size: int,
                   main_memory: int,
                   slave_memory: int = None,
                   type: int = 3,
                   time: str):

    create_compute(
        db,
        compute=Compute(
            service_id=service_id,
            mainnode=mainnode,
            size=size,
            main_memory=main_memory,
            slave_memory=slave_memory,
            type=type,
            time=time
        )
    )


class ComputeCreator(metaclass=ABCMeta):
    @abstractmethod
    def create(self) -> str:
        pass


class ComputeCreatorImpl(ComputeCreator):
    prefix = 'COMPUTE'
    db: Session
    compute_scale: int
    compute_type: int

    main_node_memory = 128
    slave_node_memory = 128
    rand_str = ''
    port: int
    mainnode: str

    def __init__(self, db: Session, compute_type: int, compute_scale: int, main_node_memory: int = 128, slave_node_memory: int = 128) -> None:
        super().__init__()
        self.db = db
        self.compute_scale = compute_scale
        self.main_node_memory = main_node_memory
        self.slave_node_memory = slave_node_memory
        self.compute_type = compute_type

        self.rand_str = get_new_name(self.prefix)

    def get_a_rand_mainnode(self):
        a = random.randint(1, 100000)
        nodes = GetNodeList()
        a = a % (len(nodes))
        self.mainnode = nodes[a].Addr

    def create(self) -> str:
        self.get_a_rand_mainnode()
        time = datetime.datetime.now().strftime("%Y-%m-%d %H:%m:%s")[0:19]

        commit_compute(
            self.db,
            service_id=self.rand_str,
            mainnode=self.mainnode,
            size=self.compute_scale,
            main_memory=self.main_node_memory,
            slave_memory=self.slave_node_memory,
            type=self.compute_type,
            time=time
        )

        return self.rand_str


def get_compute_creator(
        db: Session,
        compute_type: int,
        compute_scale: int,
        main_node_memory: int = 128,
        slave_node_memory: int = 128) -> Optional[ComputeCreator]:
    return ComputeCreatorImpl(db=db, compute_type=compute_type, compute_scale=compute_scale, main_node_memory=main_node_memory, slave_node_memory=slave_node_memory)
